package com.ljk.util.date;


import com.ljk.util.UtilException;
import org.apache.commons.lang3.time.DateUtils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

import static com.ljk.util.date.DateConstant.*;

/**
 * java8之前的时间工具类
 *
 * @author ljk
 * @since 2024/4/8 16:06
 */
public class DateUtil {

    private DateUtil() {
    }

    protected static final String[] PARSE_PATTERNS = {
            YYYY_MM_DD, YYYY_MM_DD_HH_MM_SS, YYYY_MM_DD_HH_MM, YYYY_MM,
            "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
            "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"};


    public static Date parseDate(Object val) {
        if (val instanceof String) {
            try {
                return DateUtils.parseDate((String) val, PARSE_PATTERNS);
            } catch (ParseException e) {
                return null;
            }
        }
        return null;
    }

    public static Date parseDateFromExcelDouble(Double valDate) {
        int wholeDays = (int)Math.floor(valDate);
        int millisecondsInDay = (int)((valDate - wholeDays) * DAY_MILLISECONDS + 0.5);

        int startYear = 1900;
        int dayAdjust = -1; // Excel thinks 2/29/1900 is a valid date, which it isn't

        Calendar calendar = Calendar.getInstance();// using default time-zone
        calendar.set(startYear, Calendar.JANUARY, wholeDays + dayAdjust, 0, 0, 0);
        calendar.set(Calendar.MILLISECOND, millisecondsInDay);
        return calendar.getTime();
    }

    public enum TimeUnitEnum {
        /*时间单位*/
        YEAR, MONTH, DAY, HOUR, MINUTE, SECOND, MILLISECOND
    }


    /**
     * 根据特定格式格式化日期
     *
     * @param date   被格式化的日期
     * @param format 日期格式
     * @return 格式化后的字符串
     */
    public static String format(Date date, String format) {
        return date == null ? null : new SimpleDateFormat(format).format(date);
    }

    /**
     * 字符转时间
     *
     * @param dateStr   时间字符串
     * @param formatStr 格式
     */
    public static Date parse(String dateStr, String formatStr) {
        try {
            return new SimpleDateFormat(formatStr).parse(dateStr);
        } catch (ParseException e) {
            throw new UtilException(String.format("时间格式解析异常.参数[%s]格式[%s]", dateStr, formatStr));
        }
    }

    /** now */
    public static Date now() {
        return new Date();
    }

    /** today */
    public static Date today() {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTime();
    }

    /** 由年月日构造时间 */
    public static Date of(int year, int month, int day) {
        return of(year, month, day, 0, 0, 0);
    }

    /** 由年月日时分秒构造时间 */
    public static Date of(int year, int month, int day, int hour, int minute, int second) {
        return of(year, month, day, hour, minute, second, 0);
    }

    /**
     * 由入参构造时间
     *
     * @param year        年
     * @param month       月
     * @param day         日
     * @param hour        时
     * @param minute      分
     * @param second      秒
     * @param millisecond 毫秒
     * @author ljk
     * @since 2024/4/17 14:23
     */
    public static Date of(int year, int month, int day, int hour, int minute, int second, int millisecond) {
        --month;
        if (Calendar.JANUARY > month || month > Calendar.DECEMBER) {
            throw new UtilException("month ∈ [Calendar.JANUARY,Calendar.DECEMBER]");
        }
        // 使用Calendar类调整日期和时间
        Calendar calendar = Calendar.getInstance();
        calendar.set(year, month, day, hour, minute, second);
        calendar.set(Calendar.MILLISECOND, millisecond);
        return calendar.getTime();
    }

    public static int compareTo(Date left, Date right) {
        if (left == null || right == null) {
            int i = (left == null) ? -1 : 0;
            return (right == null) ? ++i : i;
        }
        return left.compareTo(right);
    }


    /**
     * 获取指定日期时间加上指定数量日期时间单位之后的日期时间.
     *
     * @param date         日期时间
     * @param num          数量
     * @param timeUnitEnum 日期时间单位
     * @return 新的日期时间
     */
    public static Date dateAdd(Date date, int num, TimeUnitEnum timeUnitEnum) {
        if (date == null) {
            return null;
        }
        int unit;
        switch (timeUnitEnum) {
            case YEAR:
                unit = Calendar.YEAR;
                break;
            case MONTH:
                unit = Calendar.MONTH;
                break;
            case DAY:
                unit = Calendar.DATE;
                break;
            case HOUR:
                unit = Calendar.HOUR_OF_DAY;
                break;
            case MINUTE:
                unit = Calendar.MINUTE;
                break;
            case SECOND:
                unit = Calendar.SECOND;
                break;
            case MILLISECOND:
                unit = Calendar.MILLISECOND;
                break;
            default:
                throw new UtilException("未知单位");
        }
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(unit, num);
        return calendar.getTime();
    }

    /**
     * 获取指定日期时间减去指定数量日期时间单位之后的日期时间.
     *
     * @param date         日期时间
     * @param num          数量
     * @param timeUnitEnum 日期时间单位
     * @return 新的日期时间
     */
    public static Date dateSub(Date date, int num, TimeUnitEnum timeUnitEnum) {
        return dateAdd(date, -1 * num, timeUnitEnum);
    }

    /** 获取一天的开始时间 */
    public static Date atStartOfDay(Date date) {
        return atTime(date, 0, 0, 0, 0);
    }

    /** 获取一天的结束时间 */
    public static Date atEndOfDay(Date date) {
        return atTime(date, 23, 59, 59, 999);
    }

    public static Date atTime(Date date, Integer hour, Integer minute, Integer second) {
        return changeDateTime(date, null, null, null, hour, minute, second, null);
    }

    /** 修改时分秒 */
    public static Date atTime(Date date, Integer hour, Integer minute, Integer second, Integer millisecond) {
        return changeDateTime(date, null, null, null, hour, minute, second, millisecond);
    }

    /** 修改年月日时分秒 */
    public static Date changeDateTime(Date date, Integer year, Integer month, Integer day, Integer hour, Integer minute, Integer second, Integer millisecond) {
        if (date == null) {
            return null;
        }
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        if (year != null) {
            calendar.set(Calendar.YEAR, year);
        }
        if (month != null) {
            calendar.set(Calendar.MONTH, month);
        }
        if (day != null) {
            calendar.set(Calendar.DATE, day);
        }
        if (hour != null) {
            calendar.set(Calendar.HOUR_OF_DAY, hour);
        }
        if (minute != null) {
            calendar.set(Calendar.MINUTE, minute);
        }
        if (second != null) {
            calendar.set(Calendar.SECOND, second);
        }
        if (millisecond != null) {
            calendar.set(Calendar.MILLISECOND, millisecond);
        }
        return calendar.getTime();
    }

    public static Date calcFirstDayOfBirthYear(int age) {
        return dateAdd(dateSub(today(), age + 1, TimeUnitEnum.YEAR), 1, TimeUnitEnum.DAY);
    }

    public static Date calcLastDayOfBirthYear(int age) {
        return dateSub(today(), age, TimeUnitEnum.YEAR);
    }


}
